package com.utils;

import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;

/**
 * 采用MD5加密解密
 */
public class MD5Util {

    private final static Log log = LogFactory.getLog(MD5Util.class);

    /**
     * MD5加码 生成32位md5码
     */
    public static String string2MD5(String inStr) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (Exception e) {
            System.out.println(e.toString());
            e.printStackTrace();
            return "";
        }
        char[] charArray = inStr.toCharArray();
        byte[] byteArray = new byte[charArray.length];

        for (int i = 0; i < charArray.length; i++)
            byteArray[i] = (byte) charArray[i];
        byte[] md5Bytes = md5.digest(byteArray);
        StringBuffer hexValue = new StringBuffer();
        for (int i = 0; i < md5Bytes.length; i++) {
            int val = ((int) md5Bytes[i]) & 0xff;
            if (val < 16)
                hexValue.append("0");
            hexValue.append(Integer.toHexString(val));
        }
        return hexValue.toString();

    }

    /**
     * 加密解密算法 执行一次加密，两次解密
     */
    public static String convertMD5(String inStr) {

        char[] a = inStr.toCharArray();
        for (int i = 0; i < a.length; i++) {
            a[i] = (char) (a[i] ^ 't');
        }
        String s = new String(a);
        return s;

    }

    /**
     * 计算文件md5值
     * @param filePath 文件地址
     * @return
     */
    public static String fileMD5(String filePath){
        // 缓冲区大小
        int bufferSize = 256 * 1024;

        FileInputStream fileInputStream = null;
        DigestInputStream digestInputStream = null;

        try {
            MessageDigest messageDigest =MessageDigest.getInstance("MD5");

            // 使用DigestInputStream
            fileInputStream = new FileInputStream(filePath);
            digestInputStream = new DigestInputStream(fileInputStream,messageDigest);
            // read的过程中进行MD5处理，直到读完文件
            byte[] buffer =new byte[bufferSize];
            while (digestInputStream.read(buffer) > 0);
            // 获取最终的MessageDigest
            messageDigest= digestInputStream.getMessageDigest();
            // 拿到结果，也是字节数组，包含16个元素
            byte[] resultByteArray = messageDigest.digest();
            // 同样，把字节数组转换成字符串
            return byteArrayToHex(resultByteArray);
        } catch (Exception e) {
            log.error("文件md5公用模块出现异常，内容为：", e);
            return null;
        } finally {
            try {
                digestInputStream.close();
            } catch (Exception e) {
                log.error("文件md5公用模块出现异常，内容为：", e);
            }
            try {
                fileInputStream.close();

            } catch (Exception e) {
                log.error("文件md5公用模块出现异常，内容为：", e);
            }

        }

    }

    /**
     * 对 MultipartFile 文件流进行MD5
     * @param mf  文件
     * @return  MD5
     */
    public static String ioMD5(MultipartFile mf){
        // 缓冲区大小
        int bufferSize =1024;
        InputStream in=null;

        try {
            in= mf.getInputStream();
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            int nread=0;

            byte[] dataBytes=new byte[bufferSize];

            while ((nread=in.read(dataBytes))!=-1){
                md5.update(dataBytes,0,nread); //update the digest using the specified array of bytes
            }

            byte[] mdbytes= md5.digest();//完成hash算法

            return MD5Util.byteArrayToHex(mdbytes);

        } catch (Exception e) {
            log.error("文件流 md5公用模块出现异常，内容为：", e);
            return null;
        } finally {
            if(null!=in){
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("文件流 md5公用模块出现异常，内容为：", e);
                }
            }
        }


    }

    /**
     * 字节数组换成16进制的字符串
     * @param byteArray
     * @return
     */
    public static String byteArrayToHex(byte[] byteArray) {
        // 首先初始化一个字符数组，用来存放每个16进制字符
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        // new一个字符数组，这个就是用来组成结果字符串的（解释一下：一个byte是八位二进制，也就是2位十六进制字符（2的8次方等于16的2次方））
        char[] resultCharArray = new char[byteArray.length * 2];
        // 遍历字节数组，通过位运算（位运算效率高），转换成字符放到字符数组中去
        int index = 0;

        for (byte b : byteArray) {
            resultCharArray[index++] = hexDigits[b >>> 4 & 0xf];
            resultCharArray[index++] = hexDigits[b & 0xf];
        }
        return new String(resultCharArray);
    }

        // 测试主函数
    public static void main(String args[]) {
        String s = "admin";
        System.out.println("原始：" + s);
        System.out.println("MD5后：" + string2MD5(s));
        System.out.println("加密的：" + convertMD5(s));
        System.out.println("解密的：" + convertMD5(convertMD5(s)));

    }
}
